/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2024年6月26日
 * V4.0
 */
package com.jphenix.driver.threadpool;

//#region 【引用区】
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.jphenix.standard.docs.ClassInfo;
//#endregion

//#region 【类说明区】
/**
 * 线程桶，用来管理一组线程
 * com.jphenix.driver.threadpool.ThreadBucket
 * @author MBG
 * 2024年6月26日
 */
//#endregion
@ClassInfo({"2024-06-26 14:12","线程桶，用来管理一组线程"})
public class ThreadBucket {
	
	//#region 【变量声明区】
	private String       name        = null; // 线程桶名
	private ThreadGroup  threadGroup = null; // 对应的线程组对象
	private ThreadBucket parent      = null; // 父桶对象
	// 线程序列
	private List<Thread> threadList      = new ArrayList<>();
	// 子桶对象序列
	private List<ThreadBucket> childList = new ArrayList<>();
	//#endregion

	//#region 【构造函数】
	/**
	 * 构造函数
	 */
	public ThreadBucket() {
		super();
		this.name = "ThreadBucket";
		initThreadGroup(); //初始化线程分组
	}
	
	/**
	 * 构造函数
	 * @param  name 线程桶名
	 */
	public ThreadBucket(String name) {
		super();
		this.name = name;
		initThreadGroup(); //初始化线程分组
	}
	
	/**
	 * 构造函数
	 * @param parent 父桶对象
	 */
	public ThreadBucket(ThreadBucket parent) {
		super();
		this.name = "ThreadBucket";
		this.parent = parent;
		initThreadGroup(); //初始化线程分组
	}
	
	/**
	 * 构造函数
	 * @param parent
	 * @param name
	 */
	public ThreadBucket(ThreadBucket parent,String name) {
		super();
		this.name   = name;
		this.parent = parent;
		initThreadGroup(); //初始化线程分组
	}
	//#endregion
	
	//#region add(runnable) 添加这个Runnable并作为线程启动
	/**
	 * 添加这个Runnable并作为线程启动
	 * @param runnable 需要运行的程序
	 * @return         在线程桶中的线程序号
	 * 
	 * runnable 可以用 lambda 创建，很简单，比如：
	 * 
	 * add(()->{
	 *   //run方法中的代码
	 * });
	 */
	public synchronized int add(Runnable runnable) {
		// 构建线程
		Thread thread = new Thread(threadGroup,runnable,name+"-"+(threadList.size()+1));
		threadList.add(thread);
		thread.start();
		return threadList.size()-1;
	}
	//#endregion
	
	//#region add(threadName,runnable) 添加这个Runnable并作为线程启动
	/**
	 * 添加这个Runnable并作为线程启动
	 * @param threadName 线程名
	 * @param runnable   需要运行的程序
	 * @return           在线程桶中的线程序号
	 * 
	 * runnable 可以用 lambda 创建，很简单，比如：
	 * 
	 * add(()->{
	 *   //run方法中的代码
	 * });
	 */
	public synchronized int add(String threadName,Runnable runnable) {
		if(threadName==null || threadName.length()<1) {
			threadName = name+"-"+(threadList.size()+1);
		}
		// 构建线程
		Thread thread = new Thread(threadGroup,runnable,threadName);
		threadList.add(thread);
		thread.start();
		return threadList.size()-1;
	}
	//#endregion

	//#region add(child) 添加子桶对象
	/**
	 * 添加子桶对象
	 * @param child 子桶对象
	 */
	public void add(ThreadBucket child) {
		if(!childList.contains(child)) {
			childList.add(child);
		}
	}
	//#endregion
	
	//#region getThreadGroup() 返回当前线程桶对应的线程分组对象
	/**
	 * 返回当前线程桶对应的线程分组对象
	 * @return 线程分组对象
	 */
	public ThreadGroup getThreadGroup() {
		return threadGroup;
	}
	//#endregion
	
	//#region get(index) 通过线程序号（add方法的返回值）获取指定线程
	/**
	 * 通过线程序号（add方法的返回值）获取指定线程
	 * @param index 线程序号 （add方法的返回值）
	 * @return      指定线程
	 */
	public Thread get(int index) {
		if(index<0 || index>=threadList.size()) {
			return null;
		}
		return threadList.get(index);
	}
	//#endregion
	
	//#region list() 返回当前线程桶中所有线程序列
	/**
	 * 返回当前线程桶中所有线程序列
	 * @return 当前线程桶中所有线程序列
	 */
	public List<Thread> list(){
		return threadList;
	}
	//#endregion

	//#region childs() 返回子桶序列
	/**
	 * 返回子桶序列
	 * @return 子桶序列
	 */
	public List<ThreadBucket> childs(){
		return childList;
	}
	//#endregion
	
	//#region activeCount() 返回当前线程桶中，活动线程的数量
	/**
	 * 返回当前线程桶中，活动线程的数量
	 * @return 当前线程桶中，活动线程的数量
	 */
	public int activeCount() {
		return threadGroup.activeCount();
	}
	//#endregion
	
	//#region getName() 返回当前线程桶名
	/**
	 * 返回当前线程桶名
	 * @return 线程分组名
	 */
	public String getName() {
		return name;
	}
	//#endregion
	
	//#region parent() 返回父桶对象
	/**
	 * 返回父桶对象
	 * @return 父桶对象
	 */
	public ThreadBucket parent() {
		return parent;
	}
	//#endregion
	
	//#region interrupt() 中断桶中全部线程（包含子桶中的全部线程）
	/**
	 * 中断桶中全部线程（包含子桶中的全部线程）
	 */
	public void interrupt() {
		for(Thread ele:threadList) {
			ele.interrupt();
		}
	}
	//#endregion
	
	//#region join() 等待桶中所有线程都执行完毕后取消阻塞
	/**
	 * 等待桶中所有线程都执行完毕后取消阻塞
	 * @throws 被中断时发生异常
	 */
	public void join() throws InterruptedException {
		for(ThreadBucket ele:childList) {
			ele.join();
		}
		for(Thread ele:threadList) {
			ele.join();
		}
	}
	//#endregion
	
	//#region join(threadCount) 当指定数量的线程都处于活动状态时，执行阻塞，直到低于该数量放行
	/**
	 * 当指定数量的线程都处于活动状态时，执行阻塞，直到低于该数量放行
	 * 
	 * 注意：该方法仅对当前线程桶做统计，不包含子线程桶
	 * 
	 * @param threadCount 指定线程数量
	 */
	public void join(int threadCount) {
		while(threadGroup.activeCount()>=threadCount) {
			try {
				Thread.sleep(200);
			}catch(Exception e) {
				e.printStackTrace();
				break;
			}
		}
	}
	//#endregion
	
	//#region join(millis) 等待桶中所有线程都执行完毕后取消阻塞
	/**
	 * 等待桶中所有线程都执行完毕后取消阻塞
	 * @param millis 指定毫秒数超时取消阻塞
	 * @throws 被中断时发生异常
	 */
	public void join(long millis) throws InterruptedException {
		for(ThreadBucket ele:childList) {
			ele.join(millis);
		}
		for(Thread ele:threadList) {
			ele.join(millis);
		}
	}
	//#endregion
	
	//#region isAlive() 该桶中是否还有活动线程（包含子桶中的线程）
	/**
	 * 该桶中是否还有活动线程（包含子桶中的线程）
	 */
	public boolean isAlive() {
		for(Thread ele:threadList) {
			if(ele.isAlive()) {
				return true;
			}
		}
		for(ThreadBucket ele:childList) {
			if(ele.isAlive()) {
				return true;
			}
		}
		return false;
	}
	//#endregion
	
	//#region 【内部方法】initThreadGroup(name)
	/**
	 * 初始化线程分组
	 */
	private void initThreadGroup() {
		threadGroup = new ThreadGroup(
				name+"-"+(new SimpleDateFormat("HHmmss-SSS")).format(new Date()));
	}
	//#endregion
}








